package biolean.files;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import biolean.Biolean;
import biolean.FileForm;
import biolean.Utils;
import biolean.commands.Command;
import biolean.logic.GraphicElement;
import biolean.logic.Project;

public class BioFile extends GraphicElement
{	

	protected BufferedReader mReader;
	protected BufferedWriter mWriter;
	protected String mPath;
	protected IOTYPE mType;
	protected Date mDate;
	
	
	public void openReader() throws IOException
	{
		mReader = new BufferedReader( new FileReader(mPath) );
	}
	
	public boolean isRoot()
	{
		return mInPuts.size() == 0;
	}
	
	public void closeReader() throws IOException
	{
		mReader.close();
	}		
	
	public void openWriter()  throws IOException
	{
		mWriter = new BufferedWriter( new FileWriter(mPath) );
	}
	
	public void closeWriter() throws IOException
	{
		mWriter.close();
	}
	
	public boolean exists()
	{
		return new File(mPath).exists();
	}
	
	public enum IOTYPE
	{
		INPUT,
		OUTPUT,
		UNDEF
	}
	
	public BioFile()
	{
		super(0,0);
	}
	
	public BioFile(int x, int y, String path )
	{
		super(x, y);
		mType = IOTYPE.UNDEF;
		mPath = path;
	}

	public BioFile(int x, int y )
	{
		super(x, y);
		mPath = "";
		mType = IOTYPE.UNDEF;
	}
	
	public void initialize(int x , int y , String path)
	{
		this.x = x;
		this.y = y;
		mPath = path;
		//UpdateDate();
	}
	

	public String toString()
	{
		return mPath;
	}
	
	public void setIOType(IOTYPE t){mType = t;}	
	public IOTYPE getIOType(){return mType;}
	

	public boolean connectToCommand(Command command)
	{
		if (!isConnected(command) && command.canConnect(this) )
		{
			mConnection.add(command);
			command.getInputs().add(this);
			command.pushFileType(this);
			return true;
		}
		return false;
	}
	
	public boolean disconnectFromCommand(Command command)
	{
		if ( isConnected( command) )
		{
			mConnection.remove( command );
			command.getInputs().remove( this );
			command.popFileType(this );
			return true;
		}
		return false;
	}
	

	
	public void draw(Graphics g) {
		Color color;
		if (getActive()) {
			color = Color.blue;
		}
		else if (isReady() && DateOK()  ){
			color = new Color(0,150,0);
		}
		else {
			color = Color.red;
		}
		//color = (getActive())? Color.blue : Color.black;
		setSizes(g);
		Graphics2D g2 = (Graphics2D) g;
		g2.setStroke(ELEMENT_LINE_WIDTH);
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(color);
		g2.drawRect(x - width/2, y - FILE_HEIGHT/2, width, FILE_HEIGHT);
		 g2.getFontMetrics(NORMAL_FONT);
		g2.setFont(NORMAL_FONT);
		g2.drawString(getFileName(), x - width/2 + 10, y - FILE_HEIGHT/2 + 20);
    }
	
	public void addToXML(Document doc , Element root) throws ParserConfigurationException, TransformerException
	{
		Element file = doc.createElement(Project.XML_FILE);
		Attr attrType = doc.createAttribute(Project.XML_TYPE);
		Attr attrX = doc.createAttribute(Project.XML_X);
		Attr attrY = doc.createAttribute(Project.XML_Y);
		attrType.setNodeValue(Biolean.fileRegister.findTypeName(this.getClass() ) );
		attrX.setNodeValue( Integer.toString(x) );
		attrY.setNodeValue( Integer.toString(y) );
		
		file.setAttributeNode(attrType);
		file.setAttributeNode(attrX);
		file.setAttributeNode(attrY);

		
		Element path = doc.createElement(Project.XML_PATH);
		Element date = doc.createElement(Project.XML_DATE);
		Element ready = doc.createElement(Project.XML_READY);

		ready.setTextContent( mReady == true ? Project.XML_TRUE : Project.XML_FALSE);
		
		path.setTextContent(mPath);
		String strdate = mDate != null ? Long.toString( mDate.getTime() ) : Project.XML_NULL;
		date.setTextContent( strdate );
		
		file.appendChild(path);
		file.appendChild(date);
		file.appendChild(ready);
		
		root.appendChild(file);
	}
	
	public static GraphicElement loadFromXML(Node fileNode)
	{
		BioFile result = null;
		
		NamedNodeMap attrMap = fileNode.getAttributes();
		NodeList nodeMap = fileNode.getChildNodes();
		int x = Integer.parseInt( attrMap.getNamedItem(Project.XML_X).getTextContent() );
		int y = Integer.parseInt( attrMap.getNamedItem(Project.XML_Y).getTextContent() );
		String type = attrMap.getNamedItem(Project.XML_TYPE).getTextContent();
		Class<?> cls = Biolean.fileRegister.findClass( type );
		if (cls == null)
			return null;
		try {
			result = (BioFile) cls.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		String strPath =  Utils.findNode(nodeMap, Project.XML_PATH).getTextContent();
		String strReady = Utils.findNode(nodeMap, Project.XML_READY).getTextContent();
		String strDate =  Utils.findNode(nodeMap, Project.XML_DATE).getTextContent();
		
		result.setReady( strReady.equals(Project.XML_TRUE) ? true : false );
		
		result.mDate = strDate.equals(Project.XML_NULL ) ? null : new Date( Long.parseLong( strDate ) );
		
		result.initialize(x, y, strPath);
		return result;
	}
	
	public Date getModifiedDate()
	{
		Date result = null;
		File f = new File(mPath); 
		if ( f.exists() ) 
		{
			result = new Date(  f.lastModified() );
		}
		return result;
	}
	
	
	public void UpdateDate()
	{
		mDate = getModifiedDate();
	}
	
	public boolean DateOK()
	{
		if (mDate == null)
			return true;
		File f = new File(mPath);
		Date d= getModifiedDate();
		return f.exists() && mDate.equals( d );
		
	}
	
	public void setFilePath(String path) {
		mPath = path;
	}
	
	public String getFilePath() {
		return mPath;
	}
	
	public String getFileName() {
		String fileName = mPath;
		int idx = fileName.lastIndexOf("\\");
		return idx >= 0 ? fileName.substring(idx + 1) : fileName;
	}
	
	private void setSizes(Graphics g) {
		String fileName = getFileName();
		FontMetrics fm =  g.getFontMetrics(BOLD_FONT);
		int textWidth = fm.stringWidth(fileName);
		width = textWidth + 10;

	}
	
	public void performDoubleClick()
	{
		new FileForm(this);
	}
}
